#include "ServerApp.h"
#include <boost/lexical_cast.hpp>
#include "utils/XmlParser.h"
#include "boost/algorithm/string.hpp"
ServerApp::ServerApp()
{
	m_pTimerManager = NULL;
	m_Timer_Check_Socket = 0;
}


ServerApp::~ServerApp()
{
	if (m_pPropertyParser)
	{
		delete m_pPropertyParser;
	}
	m_pPropertyParser = NULL;

	if (m_pTimerManager)
	{
		delete m_pTimerManager;
		m_pTimerManager = NULL;
	}
}

void ServerApp::Process(SocketID socketID,
						int cmd, const void * pBuffer, uint32_t size,
						const boost::function< void() > & fun_callback)
{
	boost::shared_lock<boost::shared_mutex> lock(m_singals_lock);
	std::pair<ITER, ITER> ret = m_MessageHandlerMap.equal_range(cmd);

	for (ITER it = ret.first; it != ret.second; ++it)
	{
		it->second.handler(socketID, cmd, pBuffer, size);
	}

	if (fun_callback)
	{
		fun_callback();
	}
}

void ServerApp::registerCmdHandler(int cmd, void *pKey ,const MessageHandler & handler)
{
	boost::unique_lock<boost::shared_mutex> lock(m_singals_lock);
	Handler h;
	h.key = pKey;
	h.handler = handler;
	m_MessageHandlerMap.insert(std::make_pair(cmd, h));
}

void ServerApp::unregisterCmdHandler(int cmd, void* pKey)
{
	boost::unique_lock<boost::shared_mutex> lock(m_singals_lock);
	std::pair<ITER, ITER> ret = m_MessageHandlerMap.equal_range(cmd);

	for (ITER it = ret.first; it != ret.second; ++it)
	{
		if (it->second.key == pKey)
		{
			m_MessageHandlerMap.erase(it);
		}		
	}
}

IPropertyParser* ServerApp::getPropertyParser()
{
	return m_pPropertyParser;
}

bool ServerApp::start(const char * config_file, boost::asio::io_service * pIOService)
{
	m_LoggerManager.Init("./logger.xml");

	XmlParser *pParser = new XmlParser();
	if (!pParser->loadFromFile(config_file))
	{
		delete pParser;
		return false;
	}

	m_pPropertyParser = pParser;

	m_pTimerManager = new TimerManager(pIOService);

	StartSessionManager();
	LoadModules();

	int expired_time = m_pPropertyParser->getInteger(NULL, "base.listen.expired_time");

	m_Timer_Check_Socket = m_pTimerManager->schedule(0, expired_time*1000,
		boost::bind(&ServerApp::check_expired_socket, this, expired_time));

	return true;
}

void ServerApp::StartSessionManager()
{
	if (m_pPropertyParser == NULL)
	{
		return;
	}

	NodeToken rootToken = m_pPropertyParser->getRoot();
	//start session manager
	int nThreadCount = m_pPropertyParser->getInteger(rootToken, "base.thread.count", boost::thread::hardware_concurrency());
	std::string tcps = m_pPropertyParser->getString(rootToken, "base.listen.tcp.ports");
	std::string https = m_pPropertyParser->getString(rootToken, "base.listen.http.ports");

	std::vector<boost::asio::ip::tcp::endpoint> tcp_eps;
	std::vector<std::string> keys;
	boost::algorithm::split(keys, tcps, boost::algorithm::is_any_of(",;|"));

	for (size_t n = 0; n < keys.size(); ++n)
	{
		unsigned short usPort = boost::lexical_cast<unsigned short>(keys[n]);
		boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), usPort);
		tcp_eps.push_back(endpoint);
	}

	std::vector<boost::asio::ip::tcp::endpoint> http_eps;
	boost::algorithm::split(keys, https, boost::algorithm::is_any_of(",;|"));

	for (size_t n = 0; n < keys.size(); ++n)
	{
		unsigned short usPort = boost::lexical_cast<unsigned short>(keys[n]);
		boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), usPort);
		http_eps.push_back(endpoint);
	}

	m_SessonManager.Start(nThreadCount, tcp_eps, http_eps);
}

void ServerApp::LoadModules()
{
	NodeToken rootToken = m_pPropertyParser->getRoot();
	NodeToken plugins = m_pPropertyParser->GetSubNode(rootToken, "plugins");

	if (plugins != NULL)
	{
		NodeToken module = m_pPropertyParser->GetSubNode(plugins, "");
		while (module)
		{
			std::string name = m_pPropertyParser->getKeyName(module);
			std::string path = m_pPropertyParser->getString(module, "path");
			
			if (!name.empty()
				&& !path.empty())
			{
				m_ModuleManager.LoadModule(name.c_str(), path.c_str(), this);
			}

			module = m_pPropertyParser->GetNextNode(module, NULL);
		}
	}
}

ISessionManager* ServerApp::getSessionManager()
{
	return &m_SessonManager;
}

ITimerManager* ServerApp::getTimerManager()
{
	return m_pTimerManager;
}

void ServerApp::stop()
{
	if (m_pTimerManager)
	{
		delete m_pTimerManager;
		m_pTimerManager = NULL;
	}

	{
		boost::unique_lock<boost::shared_mutex> lock(m_singals_lock);
		m_MessageHandlerMap.clear();
	}

	m_SessonManager.StopAll();
	m_ModuleManager.UnloadAllModules();

}

void ServerApp::check_expired_socket(int expired_max)
{
	m_SessonManager.check_socket(expired_max);
	m_TCPClient.check_socket(expired_max);

	m_Timer_Check_Socket = m_pTimerManager->schedule(m_Timer_Check_Socket, expired_max*1000,
		boost::bind(&ServerApp::check_expired_socket, this, expired_max));
}

ITCPClient* ServerApp::getTCPClient()
{
	return &m_TCPClient;
}

ILoggerManager* ServerApp::getLoggerManager()
{
	return &m_LoggerManager;
}

ServerApp& GetServerApp()
{
	static ServerApp app;
	return app;
}
